package com.haotian.redis.cluster;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Set;

import com.haotian.redis.base.RedisClusterBase;
import com.haotian.redis.config._RedisConfig;

import redis.clients.jedis.HostAndPort;

public class _RedisClusterHash extends RedisClusterBase {

	public _RedisClusterHash(Set<HostAndPort> nodes, _RedisConfig config, int connectionTimeout, int soTimeout,
			int maxAttempts, String password) {
		super(nodes, config, connectionTimeout, soTimeout, maxAttempts, password);
	}

	private final String LOCK_FUX_ = "LOCK:";

	/**
	 * 阻塞获得锁
	 * 
	 * 判断锁是否过期 当前时间大于过期时间 为正常的判断;
	 * 
	 * getset 方法是为了避免 并发时多个线程同时覆盖value的情况
	 * 
	 * getset为原子操作 那么只要有人覆盖了 时间就会比我们的本地时间要大 所以跳出 继续等待
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public final void lock(String key) throws Exception {
	String	lockkey = LOCK_FUX_ + key;
		
			//如果 ==0 代表存在 进入循环 等待获取锁
			while (cluster.setnx(lockkey, String.valueOf(System.currentTimeMillis() + 5000)) == 0) {
				//当前时间大于过期时间的前提下 必须大于 旧的值 并同时设置新的值如果不大于旧的值证明被其他机器并行设置了，则继续等待锁释放或过期
				if (System.currentTimeMillis() > Long.valueOf(cluster.get(lockkey)) && System.currentTimeMillis() > Long
						.valueOf(cluster.getSet(lockkey, String.valueOf(System.currentTimeMillis() + 5000)))) {
					break;
				}
				try {
					Thread.sleep(250);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
	}

	/**
	 * 释放锁
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public final void reLock(String key) throws Exception {
		key = LOCK_FUX_ + key;
		this.del(key);
	}

	/**
	 * 检查key是否已经存在
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public final boolean exists(String key) throws Exception {
		return cluster.exists(key);
	}

	/**
	 * 检查key是否已经存在
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public final boolean exists(byte[] key) throws Exception {
		return cluster.exists(key);
	}

	/**
	 * 通过key删除
	 * 
	 * @param key
	 * @throws Exception
	 */
	public final long del(byte[] key) throws Exception {
		return cluster.del(key);
	}

	/**
	 * 通过key删除
	 * 
	 * @param key
	 * @throws Exception
	 */
	public final long del(String key) throws Exception {
		return cluster.del(key);
	}

	/**
	 * 存入Object 序列化对象 无超时时间
	 * 
	 * @param key
	 * @param object
	 * @return
	 * @throws Exception
	 */
	public final String setObject(byte[] key, Object object) throws Exception {
		try (ByteArrayOutputStream out = new ByteArrayOutputStream();
				ObjectOutputStream oos = new ObjectOutputStream(out);) {
			oos.writeObject(object);
			oos.flush();
			byte[] value = out.toByteArray();
			return this.set(key, value);
		}
	}

	/**
	 * 存入Object 序列化对象 带超时时间
	 * 
	 * @param key
	 * @param object
	 * @return
	 * @throws Exception
	 */
	public final String setObject(byte[] key, Object object, int seconds) throws Exception {
		try (ByteArrayOutputStream out = new ByteArrayOutputStream();
				ObjectOutputStream oos = new ObjectOutputStream(out);) {
			oos.writeObject(object);
			oos.flush();
			byte[] value = out.toByteArray();
			return this.set(key, value, seconds);
		}
	}

	public final Object getObject(byte[] key) throws Exception {
		byte[] buf = this.get(key);
		if (null == buf) {
			return null;
		}
		try (ByteArrayInputStream in = new ByteArrayInputStream(buf);
				ObjectInputStream ois = new ObjectInputStream(in);) {
			return ois.readObject();
		}
	}

	public final String set(byte[] key, byte[] value, int seconds) throws Exception {
		return cluster.setex(key, seconds, value);
	}

	public final String set(String key, String value, int seconds) throws Exception {
		return cluster.setex(key, seconds, value);
	}

	public final String set(String key, String value) throws Exception {
		return cluster.set(key, value);
	}

	public final String set(byte[] key, byte[] value) throws Exception {
		return cluster.set(key, value);
	}

	public final String get(String key) throws Exception {
		return cluster.get(key);
	}

	public final byte[] get(byte[] key) throws Exception {
		return cluster.get(key);
	}

}
